<?php

/**
 *  库存操作
 */

namespace app\api\service;

use app\api\exception\ThrowException;
use app\api\model\WholesalOrder;
use app\common\BusinessLog;
use app\common\InventoryChangeRecord;
use app\api\model\InventoryChangeRecord as InventoryChangeRecordModel;
use app\common\RabbitMQClient;
use think\Exception;
use think\facade\Config;
use \app\api\model\Order as OrderMdoel;
use think\facade\Db;
use think\facade\Lang;
use think\facade\Log;

class Inventory
{
    /**
     *   锁定库存
     */
    public function locking($data, $type = null)
    {
        foreach ($data as $value) {
            $quantity = $value['quantity'];

            // 查询具体库存记录，并加锁
            $inventoryList = Db::name('inventory')
                ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty')
                ->whereFindInSet('wid', $value['warehouse_id'])
                ->where([
                    'is_del' => 0,
                    'is_sale' => 1,
                    'productid' => $value['product_id'],
                    'arrival_date' => $value['arrival_date'],
                    'is_futures' =>  $value['is_futures'],
                    ['available_qty', '>', 0],
                ])
                ->lock(true)
                ->select();

            foreach ($inventoryList as $key => $inventory) {

                if ($quantity <= 0) {
                    break;
                }

                $keyongkucun = $inventory['available_qty'] - $inventory['lock_qty'];
                if ($quantity <= $keyongkucun) {
                    $lockQty = $quantity;
                    $quantity = 0;
                } else {
                    $lockQty = $keyongkucun;
                    $quantity -= $keyongkucun;
                }

                // 更新锁定库存
                Db::name('inventory')
                    ->where('id', $inventory['id'])
                    ->inc('lock_qty', $lockQty)
                    ->update();
            }

            // 如果最终的 buynum 不为 0，则说明库存不足，回滚事务
            if ($quantity > 0) {
                throw new ThrowException('common.insufficientInventory');
            }
        }
        return true;
    }

    /**
     *  释放锁定库存
     */
    public function unlock($data, $order_type)
    {

        // 获取当前订单的支付状态
        $orderPaymentResult = DB::name('order_payment')
            ->field('id, order_id, payment_method, status')
            ->where('order_id', $data['id'])
            ->select()
            ->toArray();

        // 先查询支付明细是否包含 转账的，如果有转发至另一普通队列
        if (0 !== count($orderPaymentResult)) {
            $iDiscard = false; // 是否丢弃

            foreach ($orderPaymentResult as $value) {
                if ($value['status'] != '00') { // 支付状态不是待审核 ， 说明已经支付成功，不需要转发 丢掉消息
                    $iDiscard = true;
                    break;
                }
            }

            if ($iDiscard) {
                echo  date('Y-m-d H:i:s', time()) . 'SUCCESS 支付状态非待审核，丢弃消息，order_no: ' . $data['order_no'] . '支付订单id' . $value['id'] . PHP_EOL;
                return true;
            } else {
                $rabbitMQService = new RabbitMQClient();
                try {
                    $delaySeconds = Config::get('system.back_locked_inventory_upload_voucher'); // 延迟时间，单位秒
                    $queueName = 'ordinaryQueueUploadVoucherPayment_' . $delaySeconds;

                    $message = json_encode([
                        'id' =>  $data['id'],
                        'order_type' => $order_type,
                        'status' => $data['status'],
                        'queue_type' => 2 // 1:创建，审核订单 2:上传支付凭证
                    ]);
                    $result = $rabbitMQService->sendDelayedMessage($queueName, $delaySeconds, $message);
                    echo  date('Y-m-d H:i:s', time()) . 'SUCCESS 支付明细未审核，转发至普通队列OrdinaryQueueUploadVoucherPayment，订单号,order_no: ' . $data['order_no'] . '支付订单id' . $value['id'] . PHP_EOL;
                    return true;
                } catch (\Exception $e) {
                    echo  date('Y-m-d H:i:s', time()) . 'ERRPR 支付明细未审核，转发至普通队列OrdinaryQueueUploadVoucherPayment异常，订单号,order_no: ' . $data['order_no'] . '支付订单id' . $value['id'] . 'err:' . $e->getMessage() . PHP_EOL;
                    return false;
                } finally {
                    $rabbitMQService->close();
                    return false;
                }
            }
        }

        // 下面的情况需要释放库存
        if ('order' == $order_type && 2 == $data['order_type']) { // 2经销商发货订单 ,需要释放经销商资产明细
            Db::startTrans();
            try {
                foreach ($data['item'] as $value) {
                    // 查询具体库存记录，并加锁
                    $wholesalAssetsList = Db::name('wholesal_order')
                        ->alias('a')
                        ->join('wholesal_order_item b', 'a.id = b.order_id')
                        ->field('b.id,b.lock_qty')
                        ->where([
                            'a.is_del' => 0,
                            'a.id' => $value['warehouse_id'],
                            'b.product_id' => $value['product_id'],
                        ])
                        ->select()
                        ->toArray();

                    $unLockQty = $value['quantity']; // 需要释放的库存

                    foreach ($wholesalAssetsList as $v) {
                        if ($unLockQty <= 0) {
                            break;
                        }
                        // 计算可释放的库存量
                        $availableQty = min($unLockQty, $v['lock_qty']);
                        Db::name('wholesal_order_item')
                            ->where('id', $v['id'])
                            ->update([
                                'lock_qty' => $v['lock_qty'] - $availableQty,
                            ]);
                        $unLockQty -= $availableQty;
                    }
                }

                Db::name('order')->where('id', $data['id'])->update(['status' => 70]);

                /* 写入普通订单取消日志 */
                $Business = new BusinessLog();
                $Business->logOperation($data['id'], $order_type, '经销商发货订单运费支付超时自动取消', $data['order_no']);

                echo  date('Y-m-d H:i:s', time()) . 'SUCCESS  经销商发货订单运费支付超时自动释放经销商资产,order_no: ' . $data['order_no'] . PHP_EOL;
                Db::commit();
                return true;
            } catch (\Exception $e) {
                //throw $th;
                echo date('Y-m-d H:i:s', time()) . 'ERRPR 经销商发货订单运费支付超时自动释放经销商资产异常,order_no: ' . $data['order_no'] . 'err:' . $e->getMessage() . PHP_EOL;
                Db::rollback();
                return false;
            }
        } else {  // 1普通订单，需要释放库存
            Db::startTrans();
            try {
                foreach ($data['item'] as $value) {

                    $count_quantity = $value['quantity'];

                    // 查询具体库存记录，并加锁
                    $inventoryList = Db::name('inventory')
                        ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty')
                        ->whereFindInSet('wid', $value['warehouse_id'])
                        ->where([
                            'is_del' => 0,
                            'is_sale' => 1,
                            'productid' => $value['product_id'],
                            'arrival_date' => $value['arrival_date'],
                            'is_futures' =>  $value['is_futures']
                        ])
                        ->lock(true)
                        ->select();

                    foreach ($inventoryList as $key => $inventory) {

                        if ($count_quantity <= 0) {
                            break;
                        }

                        $lock_item_qty = $inventory['lock_qty'];

                        if ($count_quantity <= $lock_item_qty) {
                            $lockQty = $count_quantity;
                            $count_quantity = 0;
                        } else {
                            $lockQty = $lock_item_qty;
                            $count_quantity = $count_quantity - $lock_item_qty;
                        }

                        // 更新锁定库存
                        Db::name('inventory')
                            ->where('id', $inventory['id'])
                            ->dec('lock_qty', $lockQty)
                            ->update();
                    }
                }


                /* 修改订单状态 */
                $orderModel = null;
                switch ($order_type) {
                    case 'order':
                        $orderModel = new OrderMdoel();
                        break;
                    case 'wholesale':
                        $orderModel = new WholesalOrder();
                        break;
                    default:
                        return false;
                }
                // 查找订单
                $result = $orderModel::where('id', $data['id'])->find();

                if (!$result) {
                    return false; // 如果没有找到订单，返回失败
                }
                // 设置状态为 70
                $order_no = $result->order_no;
                $result->status = 70;

                // 保存并记录日志
                if ($result->save()) {
                    $Business = new BusinessLog();
                    $Business->logOperation($data['id'], $order_type, '订单超时自动取消', $order_no);
                }


                echo date('Y-m-d H:i:s', time()) . 'SUCCESS 订单支付超时自动取消订单,order_no: ' . $data['order_no'] . PHP_EOL;
                Db::commit();
                return true;
            } catch (\Exception $e) {
                echo date('Y-m-d H:i:s', time()) . 'ERROR 订单支付超时自动取消订单 异常,order_no: ' . $data['order_no'] . 'err:' . $e->getMessage() . PHP_EOL;
                // 回滚事务
                Db::rollback();
                // 返回错误信息
                throw new Exception('减库存失败');
            }
        }
    }


    /**
     * 减库存
     * @param int $order_id 订单ID
     * @param string $order_type  订单类型 order OR wholesal
     * @param string $business  操作名称
     * @param string|null $remark  日志备注
     * @return array
     */
    public function reduce(int $order_id, string $order_type, string $business, string $remark = null)
    {
        switch ($order_type) {
            case 'order':
                $business_tabel_name = 'order';
                $result = OrderMdoel::with([
                    'item' => function ($query) {
                        $query->with([])->field('order_id,product_id,warehouse_id,quantity,arrival_date,is_futures');
                    },
                ])
                    ->where('id', $order_id)
                    ->where('is_del', 0)
                    ->where('status', '<', 30)
                    ->find();
                break;
            case 'wholesal':
                $business_tabel_name = 'wholesal_order';
                $result = WholesalOrder::with([
                    'item' => function ($query) {
                        $query->with([])->field('order_id,product_id,warehouse_id,quantity,arrival_date,is_futures');
                    },
                ])
                    ->where('id', $order_id)
                    ->where('is_del', 0)
                    ->where('status', '<', 30)
                    ->find();
                break;
            default:
                $reslut['code'] = 1;
                $reslut['message'] = 'Error';
                return $reslut;
        }

        if (!$result) {
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        if ($result->status >= 30) {
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        $data = $result;

        /* 记录到库存记录表 */
        Db::startTrans();
        try {
            foreach ($data['item'] as $value) {
                $count_quantity = $value['quantity'];
                // 查询具体库存记录，并加锁
                $inventoryList = Db::name('inventory')
                    ->field('id,productid,wid,arrival_date,is_futures,available_qty,lock_qty')
                    ->whereFindInSet('wid', $value['warehouse_id'])
                    ->where([
                        'is_del' => 0,
                        'is_sale' => 1,
                        'productid' => $value['product_id'],
                        'arrival_date' => $value['arrival_date'],
                        'is_futures' =>  $value['is_futures'],
                        ['available_qty', '>', 0],
                    ])
                    ->lock(true)
                    ->select();

                /* 减可用库存 */
                foreach ($inventoryList as $key => $inventory) {

                    if ($count_quantity <= 0) {
                        break;
                    }

                    $available_item_qty = $inventory['available_qty'];

                    if ($count_quantity <= $available_item_qty) {
                        $available_qty = $count_quantity;
                        $count_quantity = 0;
                    } else {
                        $available_qty = $available_item_qty;
                        $count_quantity = $count_quantity - $available_qty;
                    }

                    /* 更新锁定库存 */
                    Db::name('inventory')
                        ->where('id', $inventory['id'])
                        ->dec('available_qty', $available_qty)
                        ->dec('lock_qty', $available_qty)
                        ->update();

                    /* 库存日志记录 */
                    $log_data = [];
                    $log_data['inventory_id'] = $inventory['id'];
                    $log_data['business_tabel_name'] = $business_tabel_name;
                    $log_data['business_table_id'] = $data['id'];
                    $log_data['business'] = $business;
                    $log_data['number'] = $available_qty;
                    $log_data['remark'] = $remark;
                    $writeRecordLog = new InventoryChangeRecord();
                    $writeRecordLog->writeLog($log_data);
                }
            }

            if ($count_quantity > 0) {
                throw new ThrowException([
                    'message' => Lang::get('common.insufficientInventory')
                ]);
            }

            /* 修改订单状态 */
            switch ($order_type) {
                case 'order':
                    /* 修改普通订单状态 */
                    $result = OrderMdoel::where('id', $data['id'])->update(['status' => 30, 'pay_status' => 3]);
                    if ($result) {
                        /* 写入普通订单取消日志 */
                        $Business = new BusinessLog();
                        $Business->logOperation($data['id'], $order_type, '支付成功', $data['order_no']);
                    } else {
                        break;
                    }

                case 'wholesal':

                    /* 修改进销商订单状态 */
                    $result = WholesalOrder::where('id', $data['id'])->update(
                        [
                            'status' => 100,
                            'pay_status' => 3
                        ]
                    );

                    if ($result) {
                        /* 写入订单取消日志 */
                        $Business = new BusinessLog();
                        $Business->logOperation($data['id'], $order_type, '支付成功', $data['order_no']);
                    } else {
                        break;
                    }
            }

            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        $reslut['code'] = 0;
        $reslut['message'] = 'Success';
        return $reslut;
    }

    /**
     * 还原库存
     * @param int $order_id 订单ID
     * @param string $order_type  订单类型 order OR wholesal
     * @param string $business  操作名称
     * @param string|null $remark  日志备注
     * @return true
     * @throws ThrowException
     */
    public function restore(int $order_id, string $order_type, string $business, string $remark = null)
    {
        switch ($order_type) {
            case 'order':
                $business_tabel_name = 'order';
                $result = OrderMdoel::with([
                    'item' => function ($query) {
                        $query->with([])->field('order_id,product_id,warehouse_id,quantity,arrival_date,is_futures');
                    },
                ])
                    ->where('id', $order_id)
                    ->where('is_del', 0)
                    ->find();
                break;
            case 'wholesal':
                $business_tabel_name = 'wholesal_order';
                $result = WholesalOrder::with([
                    'item' => function ($query) {
                        $query->with([])->field('order_id,product_id,warehouse_id,quantity,arrival_date,is_futures');
                    },
                ])
                    ->where('id', $order_id)
                    ->where('is_del', 0)
                    ->find();
                break;
            default:
                $reslut['code'] = 1;
                $reslut['message'] = 'Error';
                return $reslut;
        }

        if (!$result) {
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        /* 订单状态 */
        if ($result->status < 30) {
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        /* 库存记录表 */
        $where['business_tabel_name'] = $business_tabel_name;
        $where['business_table_id'] = $order_id;
        $result_record = InventoryChangeRecordModel::where($where)->select();

        if (!$result_record) {
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        $data = $result->toArray();

        /* 记录到库存记录表 */
        Db::startTrans();

        try {
            foreach ($data as $value) {

                /* 更新锁定库存 */
                Db::name('inventory')
                    ->where('id', $value['id'])
                    ->dec('available_qty', $value['number'])
                    ->update();

                /* 库存日志记录 */
                $log_data = [];
                $log_data['inventory_id'] = $value['id'];
                $log_data['business_tabel_name'] = $business_tabel_name;
                $log_data['business_table_id'] = $data['id'];
                $log_data['business'] = $business;
                $log_data['number'] = $value['number'];
                $log_data['remark'] = $remark;
                $writeRecordLog = new InventoryChangeRecord();
                $writeRecordLog->writeLog($log_data);
            }

            if ($count_quantity > 0) {
                throw new ThrowException([
                    'message' => Lang::get('common.insufficientInventory')
                ]);
            }

            /* 修改订单状态 */
            switch ($order_type) {

                case 'order':
                    /* 修改普通订单状态 */
                    $result = OrderMdoel::where('id', $data['id'])->update(['status' => 30]);
                    if ($result) {
                        /* 写入普通订单取消日志 */
                        $Business = new BusinessLog();
                        $Business->logOperation($data['id'], $order_type, '支付成功', $data['order_no']);
                    } else {
                        break;
                    }

                case 'wholesal':

                    /* 修改进销商订单状态 */
                    $result = WholesalOrder::where('id', $data['id'])->update(['status' => 30]);

                    if ($result) {
                        /* 写入订单取消日志 */
                        $Business = new BusinessLog();
                        $Business->logOperation($data['id'], $order_type, '支付成功', $data['order_no']);
                    } else {
                        break;
                    }
            }

            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
            $reslut['code'] = 1;
            $reslut['message'] = 'Error';
            return $reslut;
        }

        $reslut['code'] = 0;
        $reslut['message'] = 'Success';
        return $reslut;
    }


    /**
     *  发送下单定时任务
     */
    public function backLockedInventoryTask($order, $order_type)
    {
        $rabbitMQService = new RabbitMQClient();

        try {
            $delaySeconds = Config::get('system.back_locked_inventory');
            $queueName = 'ordinaryQueueOrderCreate_' . $delaySeconds;
            $message = json_encode([
                'id' => $order->id,
                'order_type' => $order_type,
                'queue_type' => 1,
                'status' => $order->status
            ]);

            $rabbitMQService->sendDelayedMessage($queueName, $delaySeconds, $message);
        } catch (\Exception $e) {

            throw new ThrowException([
                'message' => $e->getMessage()
            ]);
        } finally {
            $rabbitMQService->close();
        }
    }


    /**
     *  经销商发货发送定时任务
     */
    public function wholesalOrderTask($order)
    {
        $rabbitMQService = new RabbitMQClient();
        try {
            $delaySeconds = Config::get('system.back_locked_inventory');
            $queueName = 'ordinaryQueueOrderCreate_' . $delaySeconds;
            $message = json_encode([
                'id' => $order->id,
                'order_type' => 'order',
                'queue_type' => 1,
                'status' => $order->status
            ]);
            $rabbitMQService->sendDelayedMessage($queueName, $delaySeconds, $message);
        } catch (\Exception $e) {
            throw new ThrowException([
                'message' => $e->getMessage()
            ]);
        } finally {
            $rabbitMQService->close();
        }
    }


   
}
